package com.explorex.infra.puma.gateway.netty.common;

import io.netty.channel.Channel;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;

import java.util.ArrayList;
import java.util.EventListener;
import java.util.List;
import java.util.concurrent.Semaphore;

/**
 * @author: JacceYang
 * @createTime: 2022/07/14 9:19 下午
 * @description: WebSocketEvent handler
 */
public abstract class BaseChannel {
    private final Semaphore blockExec = new Semaphore(0);
    @Getter
    protected Channel channel;
    /**
     * 工作线程池大小
     */
    @Getter
    @Setter
    protected int workerCount;
    /**
     * 是否启用keepAlive
     */
    @Getter
    @Setter
    protected boolean keepAlive = true;
    /**
     * 是否启用tcpNoDelay
     */
    @Getter
    @Setter
    protected boolean tcpNoDelay = false;
    /**
     * Sokcet参数, 存放已完成三次握手请求的队列最大长度, 默认512长度
     */
    @Setter
    @Getter
    protected int soBacklog = 1024;
    /**
     * 设置是否心跳检查
     */
    @Getter
    @Setter
    protected boolean checkHeartbeat = false;
    /**
     * 心跳检查时的读空闲时间
     */
    @Getter
    @Setter
    protected int readerIdleTimeSeconds = 300;
    /**
     * 心跳检查时的写空闲时间
     */
    @Getter
    @Setter
    protected int writerIdleTimeSeconds = 300;
    /**
     * 心跳检查时的读写空闲时间
     */
    @Getter
    @Setter
    protected int allIdleTimeSeconds = 300;
    /**
     * 编码格式
     */
    @Getter
    @Setter
    @NonNull
    protected String charsetName = "utf-8";

    protected List<EventListener> eventListeners = new ArrayList<>();
    /**
     * 主机名
     */
    @Getter
    @Setter
    private String host;
    /**
     * 端口号
     */
    @Getter
    @Setter
    private int port = 8181;

    public BaseChannel() {
        // 默认工作线程数
        this.workerCount = Runtime.getRuntime().availableProcessors() * 2+1;
        //添加JVM关闭时的勾子
        Runtime.getRuntime().addShutdownHook(new ShutdownHook(this));

        this.init();
    }

    public boolean isActive() {
        return channel != null && channel.isActive();
    }

    public boolean isOpen() {
        return channel != null && channel.isOpen();
    }

    protected void init() {

    }

    /**
     * close socket
     */
    public abstract void shutdown();

    public void addEventListener(EventListener listener) {
        this.eventListeners.add(listener);
    }

    public void requireSync() {
        try {
            blockExec.acquire();
        } catch (InterruptedException e) {
            blockExec.release();
            e.printStackTrace();
        }
    }

    public void releaseSync() {
        blockExec.release(0);
    }

    class ShutdownHook extends Thread {
        private final BaseChannel baseChannel;

        public ShutdownHook(BaseChannel baseChannel) {
            this.baseChannel = baseChannel;
        }

        @Override
        public void run() {
            releaseSync();
            baseChannel.shutdown();
        }
    }
}
